package com.vshop.timingtask;

import com.vshop.config.dto.StringOutputConstant;
import com.vshop.entity.agatewaytobeijing.JsonConstant;
import com.vshop.entity.agatewaytobeijing.openpackage.response.ResponseOpenPackage;
import com.vshop.entity.agatewaytobeijing.querydevice.beijing.response.QueryDeviceData;
import com.vshop.entity.agatewaytobeijing.querydevice.beijing.response.ResponseQueryDevice;
import com.vshop.entity.agatewaytobeijing.querydeviceorder.response.DevicePackageOrder;
import com.vshop.entity.agatewaytobeijing.querydeviceorder.response.ResponseQueryDeviceOrder;
import com.vshop.entity.agatewaytobeijing.queryh5order.response.H5PackageOrder;
import com.vshop.entity.alast.common.ServicePlanOrderRecord;
import com.vshop.entity.requestinterface.Constant;
import com.vshop.mapper.task.ServicePlanTaskMapper;
import com.vshop.service.PartnerInfoService;
import com.vshop.service.agatewaytobeijing.GatewayToBeijingService;
import com.vshop.service.alast.impl.LogicAssistService;
import com.vshop.service.alast.impl.UpgradedOrderServicePlanServiceImpl;
import com.vshop.service.impl.PurchaseLogicService;
import com.vshop.service.task.ServicePlanTaskServiceImpl;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 新版开通：
 * <p>
 * 触发停机保号期，轮询订单时，首单A未启用，
 * <p>
 * 则不启用套餐B，等待用户套餐A使用。如果存在
 * <p>
 * 多个非首单订单，则按照订购先后顺序启用
 *
 * @author lm
 * @date 2020/9/24 9:03
 */

@Configuration
@EnableScheduling
@RestController
@Api(value = "新版开通套餐（新流程）")
@Slf4j
public class ServicePlanOpenTask {
    @Value("${system.autoTask}")
    private boolean autoTask;
    @Autowired
    GatewayToBeijingService toBeijingService;
    @Autowired
    ServicePlanTaskServiceImpl taskService;
    @Autowired
    PartnerInfoService partnerInfoService;
    /**
     * 查询所有订单接口用到了
     */
    @Autowired
    PurchaseLogicService purchaseService;
    @Autowired
    LogicAssistService logicAssistService;
    @Autowired
    UpgradedOrderServicePlanServiceImpl orderServicePlanService;
    @Resource
    ServicePlanTaskMapper taskMapper;


    @Scheduled(cron = "0 0/5 * * * ?")
    @GetMapping(value = "openTask")
    @Async
    public void execute() {
        if (autoTask) {
            task();
        }
    }

    public void task() {
        //先看看有没有需要去做开通订单操作的订单列表
        List<ServicePlanOrderRecord> recordList = taskService.queryServicePlanIsOpen();
        if (null == recordList || recordList.isEmpty()) {
            return;
        }
        //把数据拿出来
        for (ServicePlanOrderRecord record : recordList) {
            String secret = partnerInfoService.getSecretByPartnerCode(record.getPartnerCode());
            //验证参数
            if (!checkParam(record, secret)) {
                continue;
            }
            //发送请求
            ResponseQueryDevice response = toBeijingService.queryDevice(record.getDeviceCode(), record.getPartnerCode(), secret);
            if (null == response) {
                continue;
            }
            //先解析一下设备查询的结果信息
            if (StringUtils.isBlank(response.getCode()) || !Constant.RET_CODE_0000.equalsIgnoreCase(response.getCode()) || null == response.getData()) {
                continue;
            }
            //验证卡片所处的生命周期和否有OTA功能
            if (!checkDeviceRealTimeInfo(response.getData(), record)) {
                continue;
            }
            /*说明接口从2.0更新到3.0了*/
            ResponseQueryDeviceOrder order = toBeijingService.queryDeviceOrder(record.getDeviceCode(), "", "", "", record.getPartnerCode(), secret);
            if (null == order || !Constant.RET_CODE_0000.equals(order.getCode()) || null == order.getData() || null == order.getData().getPackageOrder() || order.getData().getPackageOrder().isEmpty()) {
                continue;
            }
            /*将获取到的订单按照时间从最早到最晚的顺序排序*/
            List<DevicePackageOrder> orderList = orderServicePlanService.sortAsc(order.getData().getPackageOrder());
            if (null == orderList || orderList.isEmpty()) {
                continue;
            }
            /*做法：取出匹配到的时间最早的第一个订单*/
            DevicePackageOrder or = orderList.get(0);
            if (null == or) {
                continue;
            }
            /*如果最早的订单是未启用状态，就认为是首单未启用，不允许继续开通往*/
            if (StringOutputConstant.CODE_ONE.equals(or.getOrderStatus())) {
                log.info("首单是未启用状态，不允许开通");
                continue;
            }
            /*最早的订单不是未启用，可以继续走开通的路，接下来还需要判断卡片上面有没有正在使用的订单*/
            List<String> statusList = new ArrayList<>();
            /*将所有的未启用订单放到List里面*/
            List<DevicePackageOrder> finishList = new ArrayList<>();
            for (DevicePackageOrder tr : order.getData().getPackageOrder()) {
                statusList.add(tr.getOrderStatus());
                if (StringOutputConstant.CODE_ONE.equals(tr.getOrderStatus())) {
                    finishList.add(tr);
                }
            }
            /*匹配订单中是否有正在使用的订单*/
            boolean b1 = statusList.contains(StringOutputConstant.CODE_TWO);
            if (b1) {
                log.info("卡片上有正在使用的订单，不允许开通");
                continue;
            }
            /*将所有未启用的订单拿出来再去排序，从最早到最晚的顺序排序*/
            List<DevicePackageOrder> orList = orderServicePlanService.sortAsc(finishList);
            if (orList == null || orList.isEmpty()) {
                continue;
            }
            /*做法：取出匹配到的时间最早的第一个订单*/
            DevicePackageOrder firstOrder = orList.get(0);
            if (null == firstOrder) {
                continue;
            }
            /*2021-04-09修改：*/
            /*原来通用的开通套餐(/package/openPackage)：ResponseOpenPackage responseOpen = toBeijingService.openPackage(record.getPartnerCode(), order.getOrderId(), secret);*/
            /*新的专门用于商城的开通套餐接口（/package/openPackageForShop）*/

            /*2021-04-09修改：*/
            /*加了payMode参数验证的版本：ResponseOpenPackage responseOpen = toBeijingService.openPackageForShop(order.getOrderId(), secret, record);*/
            ResponseOpenPackage responseOpen = toBeijingService.openPackageForShop(firstOrder.getOrderId(), secret, record);

            if (null == responseOpen) {
                purchaseService.sendMail(record.getDeviceCode(), firstOrder.getPackageName(), firstOrder.getOrderId(), "开通套餐", "程序异常导致的开通失败");
                //记录异常操作到数据库：
                purchaseService.ExceptionRecord(record.getPartnerCode(), record.getDeviceCode(), record.getPayId(), "7", "9999", "程序异常导致的开通失败");
                log.info("【开通套餐】失败，原因：" + "程序异常导致的开通失败");
                continue;
            }

            //响应的参数都有问题
            if (StringUtils.isBlank(responseOpen.getCode()) || StringUtils.isBlank(responseOpen.getMessage())) {
                purchaseService.sendMail(record.getDeviceCode(), firstOrder.getPackageName(), firstOrder.getOrderId(), "开通套餐", "程序异常导致的开通失败");
                //记录异常操作到数据库：
                purchaseService.ExceptionRecord(record.getPartnerCode(), record.getDeviceCode(), record.getPayId(), "7", "9999", "程序异常导致的开通失败");
                log.info("【开通套餐】失败，原因：" + "程序异常导致的开通失败");
                continue;
            }

            //返回的内容不是成功
            boolean b2 = (!JsonConstant.RET_CODE_0000.equals(responseOpen.getCode()) && !JsonConstant.RET_CODE_SUCCESS.equals(responseOpen.getMessage())) || null == responseOpen.getData();
            if (b2) {
                purchaseService.sendMail(record.getDeviceCode(), firstOrder.getPackageName(), firstOrder.getOrderId(), "开通套餐", responseOpen.getMessage());
                //记录异常操作到数据库：
                purchaseService.ExceptionRecord(record.getPartnerCode(), record.getDeviceCode(), record.getPayId(), "7", "9999", responseOpen.getMessage());
                log.info("【开通套餐】失败，原因：" + responseOpen.getMessage());
                continue;
            }

            //响应是成功但是order_id是空的，只有order_id和order_start_date和order_expire_date有值才算成功开通
            if (StringUtils.isBlank(responseOpen.getData().getOrder_id())) {
                purchaseService.sendMail(record.getDeviceCode(), firstOrder.getPackageName(), firstOrder.getOrderId(), "开通套餐", "程序响应的order_id为空判定开通失败");
                //记录异常操作到数据库：
                purchaseService.ExceptionRecord(record.getPartnerCode(), record.getDeviceCode(), record.getPayId(), "7", "9999", "程序响应的order_id为空判定开通失败");
                log.info("【开通套餐】失败，原因：" + "程序异常导致的开通失败");
                continue;
            }
            /*成功开通的情况*/
            Integer openCount = updateOtaFlagIsOpen(record);
            if (openCount > 0) {
                log.info(record.getDeviceCode() + ":B2B2C下单的订单：" + firstOrder.getOrderId() + "：isOpen由0变成1,开通成功！");
            } else {
                log.info(record.getDeviceCode() + ":非B2B2C下单的订单：" + firstOrder.getOrderId() + "：开通成功！");
            }
        }
    }

    /**
     * 验证所需参数的有效性
     *
     * @param record
     * @param secret
     * @return
     */
    private boolean checkParam(ServicePlanOrderRecord record, String secret) {
        boolean flag = true;
        if (StringUtils.isBlank(secret)) {
            flag = false;
        }
        if (StringUtils.isBlank(record.getPartnerCode())) {
            flag = false;
        }
        if (StringUtils.isBlank(record.getDeviceCode())) {
            flag = false;
        }
        if (StringUtils.isBlank(record.getOrderId())) {
            flag = false;
        }
        return flag;
    }

    /**
     * 第三次循环拿出符合开通条件的订单list
     * <p>
     * 不是首单所有状态为未启用的订单list
     *
     * @param orders
     * @return
     */
    private List<H5PackageOrder> thirdCheckQueryDeviceOrder(List<H5PackageOrder> orders) {
        List<H5PackageOrder> finishList = new ArrayList<>();
        for (H5PackageOrder data : orders) {
            //只允许不是首单，且状态为未启用的订单进入
            boolean b2 = StringUtils.isNotBlank(data.getPackageCode()) && StringUtils.isNotBlank(data.getOrderCode()) && StringUtils.isNotBlank(data.getOrderStatus()) &&
                    StringUtils.isNotBlank(data.getIsFirstOrder()) && data.getOrderStatus().equals("1") && !data.getIsFirstOrder().equals("1");
            if (b2) {
                finishList.add(data);
            }
        }
        return finishList;
    }

    /**
     * 万一之前的步骤没有拦住那么现在：
     * 第二次for找出卡片有没有正在使用的订单
     * 如果有不允许往下走
     *
     * @param orders
     * @return
     */
    private boolean secondCheckQueryDeviceOrder(List<H5PackageOrder> orders) {
        boolean flag = true;
        //第二次for循环验证：首单有咩有正在使用的订单
        boolean b1 = false;
        for (H5PackageOrder t : orders) {
            b1 = StringUtils.isNotBlank(t.getPackageCode()) && StringUtils.isNotBlank(t.getOrderCode()) && StringUtils.isNotBlank(t.getOrderStatus()) && t.getOrderStatus().equals("2");
            if (b1) {
                //b1变成true时满足开通条件：首单不是未启用状态：跳出循环，执行真正的逻辑业务处理代码
                break;
            }
        }
        //for循环结果是false证明不满足条件：
        if (!b1) {
            flag = false;
        }
        return flag;
    }


    /**
     * 第一次验证首单不是未启用状态
     *
     * @param orders
     * @return
     */
    private boolean firstCheckQueryDeviceOrder(List<H5PackageOrder> orders) {
        boolean flag = true;
        //第一次for循环验证：首单不是未启用状态
        boolean b1 = false;
        for (H5PackageOrder t : orders) {
            b1 = StringUtils.isNotBlank(t.getPackageCode()) && StringUtils.isNotBlank(t.getOrderCode()) && StringUtils.isNotBlank(t.getOrderStatus()) && !t.getOrderStatus().equals("1") && StringUtils.isNotBlank(t.getIsFirstOrder()) && t.getIsFirstOrder().equals("1");
            if (b1) {
                //b1变成true时满足开通条件：首单不是未启用状态：跳出循环，执行真正的逻辑业务处理代码
                break;
            }
        }
        //for循环结果是false证明不满足条件：
        if (!b1) {
            flag = false;
        }
        return flag;
    }

    /**
     * 验证：
     * 1，设备所处的生命周期:0-库存期；1-静默期；2-使用期；3-停机保服务期；4-废弃回收期；5-内部库存期；
     * 2，是否有OTA功能，取值如下：1-有OTA功能；2-没有OTA功能；
     *
     * @param tr
     * @param record
     * @return
     */
    private boolean checkDeviceRealTimeInfo(QueryDeviceData tr, ServicePlanOrderRecord record) {
        boolean flag = true;

        //设备所处的生命周期:0-库存期；1-静默期；2-使用期；3-停机保服务期；4-废弃回收期；5-内部库存期；
        if (StringUtils.isBlank(tr.getOta_flag()) || StringUtils.isBlank(tr.getLifecycle()) || !tr.getLifecycle().equals("3")) {
            //未进停保期
            flag = false;
        }
        //是否有OTA功能，取值如下：1-有OTA功能；2-没有OTA功能；
        if (tr.getOta_flag().equals("1")) {
            /*ota设备：卡片是OTA卡片，以后再也不要发起开通了，这边把订单的isOpen状态改成1,以后不再参与轮循了*/
            updateOtaFlagIsOpen(record);
            flag = false;
        }

        return flag;
    }

    /**
     * ota设备：卡片是OTA卡片，以后再也不要发起开通了，这边把订单的isOpen状态改成1,以后不再参与轮循了
     *
     * @param record
     */
    private Integer updateOtaFlagIsOpen(ServicePlanOrderRecord record) {
        return taskMapper.updateOtaFlagIsOpen(record);
    }

    /***
     * 按照时间从最晚到最早将订单排序
     * @param rList
     * @return
     */
    public List<H5PackageOrder> sortDesc(List<H5PackageOrder> rList) {

        Collections.sort(rList, new Comparator<H5PackageOrder>() {
            @Override
            public int compare(H5PackageOrder o1, H5PackageOrder o2) {
                Date date1 = null;
                Date date2 = null;
                try {
                    date1 = new SimpleDateFormat(StringOutputConstant.CODE_DATE).parse(o1.getOrderDate());
                    date2 = new SimpleDateFormat(StringOutputConstant.CODE_DATE).parse(o2.getOrderDate());
                } catch (ParseException e) {
                    log.info("时间转换发生了异常：" + e);
                    return -1;
                }
                if (null == date1 || null == date2) {
                    return -1;
                }
                if (date1.before(date2)) {
                    return 1;
                } else if (date2 == date1) {
                    return 0;
                } else {
                    return -1;
                }
            }
        });
        return rList;

    }
}
